根据兄弟元素的数量设置样式
有时候会碰见这样一种场景:当一个列表不断延长时,通过隐藏空间或压缩控件等方式来节省屏幕空间,用来提升用户体验。
这时候就需要我们根据兄弟元素的总数来为它们设置相应的样式。
设想一个列表,假设仅当列表的总数为4时才对这些列表项设置样式,这时可以使用li:nth-child(4)来选中列表的第四个列表项。但是我们的需求却是:
在列表的总数为4时选中每个列表项
如果直接利用兄弟选择符li:nth-child(4),li:hth-child(4)~li得到的是第四个列表以及它之后的所有列表项。那么我们转换一下思路分以下几种情况:
当只有一个列表项时,直接利用:only-child即:
li:only-child{
/*只有一个列表时的样式*/
}
对于只有一个列表项的列表,其第一项同时也是该列表的最后一项。也就是说:only-child等效于:first-child:last-child,而:last-child是nth-last-child(1)的简写,所以:
li:first-child:nth-last-child(1){
/*等效于:only-child*/
}
tips :nth-last-child(n) 选择器匹配属于其元素的第 N 个子元素的每个元素,不论元素的类型,从最后一个子元素开始计数。
由上面可以得出对于一个正好包含4项的列表,如果想命中所有列表项,可以这样写:
li:first-child:nth-last-child(4),
li:first-child:nth-last-child(4)~li{
/*列表包含4项且命中所有项*/
}
根据参考手册,:nth-last-child()选择器的参数不仅仅可以是简单的数字,也可以是类似于an+b的表达式,其中,n 是计数器(从 0 开始),b 是偏移值。
比如,我们指定了下标是 3 的倍数的所有p元素的背景色,从最后一个子元素开始计数:
p:nth-last-child(3n+0){
background:#ff0000;
}
而对于n+b(相当于a=1)这个公式,无论n如何取值,这个表达式都无法产生一个小于b的值,可以选中从第b个开始的所有子元素。
因此:
li:first-child:nth-last-child(n+4),
li:first-child:nth-last-child(n+4)~li{
/*列表至少包含4项且命中所有项*/
}
同理,-n+b这种形式的表达式可以选中开头的b个元素。因此仅当列表中有4个或更少的列表时,可以这样写:
li:first-child:nth-last-child(-n+4),
li:first-child:nth-last-child(-n+4)~li{
/*列表最多包含4项且命中所有项*/
}
如果想命中包含2-6个列表项的列表时,只需把上面两种技巧组合一下:
li:first-child:nth-last-child(n+2):nth-last-child(-n+6),
li:first-child:nth-last-child(n+2):nth-last-child(-n+6)~li{
/*当列表包含2-6项时,命中列表中所有列表项*/
}
利用上面的技巧可以写一个类似于变色便签的小例子:
HTML:
<ul class="palette">
<li>
<div class="color-options">
<a class="add" href="#">Add</a>
<a class="delete" href="#">Delete</a>
</div>
<div class="input-group">
<textarea rows="12" class="form-control">write someting...</textarea>
</div>
</li>
</ul>
CSS:
<style type="text/css">
ul{
list-style: none;
}
.palette{
display: flex;
height: 300px;
max-width: 900px;
font: bold 90%/1 sans-serif;
}
.palette li{
flex: 1;
background: #D6E055;
}
.color-options{
margin: 0 10px;
padding: 10px;
background: rgba(0,0,0,.5);
border-radius: 0 0 15px 15px;
overflow: hidden;
}
.color-options a{
color: white;
text-decoration: none;
}
.color-options a:before{
display: inline-block;
font-size: 1rem;
width: 1.2rem;
margin-right: .3rem;
line-height: 1.2;
background: white;
border-radius: 50%;
text-align: center;
}
.color-options .add:before {
content:'✚';
color:#590;
}
.color-options .delete:before {
content:'✖';
color:#b00;
}
.color-options a:after {
content: ' color';
font-weight: normal;
}
.add { float:left; }
.delete { float: right; }
.palette li:only-child .delete{
display: none;
}
.palette li:first-child:nth-last-child(n+4) .color-options a:after,
.palette li:first-child:nth-last-child(n+4) ~ li .color-options a:after{
content: none;
}
.palette li:first-child:nth-last-child(n+4) .color-options a,
.palette li:first-child:nth-last-child(n+4) ~ li .color-options a{
font-size: 0;
color: transparent;
}
.input-group{
margin:20px;
}
.form-control{
width: 100%;
padding: 10px;
font: 120%/1 sans-serif;
box-sizing:border-box; /*防止溢出*/
border-radius: 15px;
outline: none;
resize: none;
}
</style>
JS:
<script type="text/javascript">
var colors = [
'#FEE169', '#CDD452', '#2E95A3', '#F9722E',
'#E6E2AF', '#A7A37E', '#EFECCA', '#046380',
'#50B8B4', '#C6FFFA', '#E2FFA8', '#D6E055','#C9313D'
],
palette = document.querySelector('.palette'),
template = palette.firstElementChild;
function addColor(template){
var li = template.cloneNode(true);
var color = colors.shift();
colors.push(color);
li.style.background = color;
// palette.insertBefore(li,template.nextSibling);
palette.appendChild(li);
}
palette.onclick = function(evt){
var button = evt.target;
if(button.className == 'add'){
addColor(button.parentNode.parentNode)
}else if(button.className == 'delete'){
if(confirm('您确定删除?')){
var li = button.parentNode.parentNode;
li.parentNode.removeChild(li);
}
}
}
</script>

紧贴底部的页脚
有一个具有块级样式的页脚,当页面内容足够长时它一切正常,而当页面比较短时,就会出现问题。此时的问题在于页脚不能像我们期望中那样“紧贴”在视口的最底部,而是紧跟在内容的下方。

上图是将内容div删掉后的天津教育考试院官网
针对于这种情况可以用下面两种方式解决:
基于固定高度的解决方案
这种方案的主要思路是:假设页脚的文本不折行,然后估算出页脚实际所占的高度。然后再计算出页头的高度。最后借助视口相关的长度单位以及calc()函数,把页脚固定到底部。其核心代码为:
main{
min-height:calc(100vh - 页头高度 - 页脚高度);
/*避免内边距或边框扰乱高度的计算*/
box-sizing:border-box;
}
举个例子,HTML:
<header>
<h1>标题</h1>
</header>
<main>
<p>
空空道人看了一回,晓得这石头有些来历,遂向石头说道:“石兄,你这一段故事,据你自己说来,有些趣味,故镌写在此,意欲闻世传奇。据我看来:第一件,无朝代年纪可考;第二件,并无大贤大忠、理朝廷、治风俗的善政,其中只不过几个异样女子,或情或痴,或小才微善。我纵然抄去,也算不得一种奇书。”石头果然答道:“我师何必太痴!我想历来野史的朝代,无非假借汉、唐的名色;莫如我这石头所记不借此套,只按自己的事体情理,反倒新鲜别致。况且那野史中,或讪谤君相,或贬人妻女,奸淫凶恶,不可胜数;更有一种风月笔墨,其淫秽污臭最易坏人子弟。至于才子佳人等书,则又开口‘文君’,满篇‘子建’,千部一腔,千人一面,且终不能不涉淫滥。在作者不过要写出自己的两首情诗艳赋来,故假捏出男女二人名姓;又必旁添一小人拨乱其间,如戏中的小丑一般。更可厌者,‘之乎者也’,非理即文,大不近情,自相矛盾。竟不如我这半世亲见亲闻的几个女子,虽不敢说强似前代书中所有之人,但观其事迹原委,亦可消愁破闷;至于几首歪诗,也可以喷饭供酒。其间离合悲欢,兴衰际遇,俱是按迹循踪,不敢稍加穿凿,至失其真。
</p>
</main>
<footer>
<p>© 2016 No rights reserved.</p>
<p>Made with ♥ by supce.</p>
</footer>
CSS:
main {
min-height: calc(100vh - 5em - 7em)
}
body {
margin: 0;
font: 100%/1.5 Palatino Linotype, Palatino, serif;
}
h1 { margin: .5em 0 0; }
header { text-align: center; height: 3em; }
main, footer {
display: block;
padding: .5em calc(50% - 400px);
}
footer {
background: linear-gradient(#222, #444);
color: white;
height: 6em;
}
效果如下:

基于flex弹性布局的解决方案
之前有一篇关于弹性布局的日志。
要想让页脚紧贴底部:
- 首先对
<body>设置display:flex;flex-flow:column;,保证body内的子元素为垂直排列。 - 其次,设置
<body>的min-height属性为100vh,这样它就至少会占据整个视口的高度。 - 最后,我们希望页头和页脚有其内部因素来决定,而内容区块的高度应该可以自动伸展并占满所有的可用空间。这就需要给
<main>这个容器的flex属性指定一个大于0的值,我们可以暂时设置为1即可。
这种方案的核心代码如下:
body{
display: flex;
flex-flow: column;
min-height: 100vh;
}
main{
flex: 1;
}
国庆节偷个小懒,不举例子了